﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

namespace Modele
{

    /* 
     * Contient la déclaration de  notes et les fontions standards .net redéfinis
     */
    [Serializable]
    public partial class Note : ICloneable
    {

        // Evénement
         [XmlIgnore]
        public EventHandler OnRythmChanged;
         [XmlIgnore]
        public EventHandler OnNoteChanged; // à implémenter

        //typage
        public enum TypeRytmique
        {
            Noire, Croche, DoubleCroche, TripleCroche, QuadrupleCroche, Ronde, Blanche,
            Pause, DemiPause, Soupir, DemiSoupir, QuartSoupir, HuitiemeSoupir, SeiziemeSoupir
        };
        public enum NoteEn { C, D, E, F, G, A, B, No };
        public enum Alteration { Bemol, Diese, Becard, No };
        public enum Langue { Fr, En };
        public enum Pointure { Pointe, DoublePointe, No };


        [XmlElement(ElementName = "Note")]
        public List<Note> noteAccord = new List<Note>();

       private TypeRytmique _rythme = TypeRytmique.Noire;
        [XmlAttribute("Rythme")]
        public TypeRytmique rythme  {
            get { return _rythme; }
            set
            {
                _rythme = value;

                if (OnRythmChanged != null)
                    OnRythmChanged(this, EventArgs.Empty);

            }
        }


        [XmlAttribute("Note")]
        public NoteEn note = NoteEn.No;

        [XmlAttribute("Alteration")]
        public Alteration alteration = Alteration.No;

        [XmlElement(ElementName = "Effets")]
        public Effets effets = new Effets(); //Représente les effets de jeux

        [Serializable]
        public class Affichage
        {

            public enum SensTige { Haut, Bas };

            [XmlAttribute("Sens")]
            public SensTige sens = SensTige.Haut;
            [XmlAttribute("Ligature")]
            public bool ligature = false; //liaison graphique
        }

        [XmlElement(ElementName = "Affichage")]
        public Affichage affichage = new Affichage();


        /* contient les infos pour afficher la note sur la tablature */
        public TablatureInfos tablatureInfos = new TablatureInfos();

        [XmlAttribute("Duree")]
        public int duree;

        private int _octave = 0;
        [XmlAttribute("Octave")]
        public int octave
        {
            get { return this._octave; }
            set { if (value <= 9 && value >= 0) { this._octave = value; } }
        }


        [XmlAttribute("Pointure")]
        public Pointure pointure = Pointure.No;

        private float _freqHz = 0;
        [XmlAttribute("Frequence")]
        public float freqHz
        {
            get { return this._freqHz; }
            set { if (value <= 48000 && value >= 0) { this._freqHz = value; } }
        }


        [XmlAttribute("Etouffe")]
        public bool estEtouffee = false;


        public Note() { this.freqHz = toFreq(); }


        /* Constructeur notament utile pour les notes du module manche */
        public Note(NoteEn note, Alteration alter, int octave)
        {

            this.note = note;
            this.alteration = alter;
            this.octave = octave;
            this.freqHz = toFreq();

        }

        public Note(TypeRytmique rythme, NoteEn note, Alteration alter, int octave, Pointure pointure, bool estEtouffee)
        {
            this.rythme = rythme;
            this.note = note;
            this.alteration = alter;
            this.octave = octave;
            this.pointure = pointure;
            this.freqHz = toFreq();
            this.estEtouffee = estEtouffee;
        }
        
        public object Clone(){

            return MemberwiseClone();

        }

        public Note Copy()
        {
            Note n = (Note)Clone();
            n.tablatureInfos = (TablatureInfos)tablatureInfos.Clone();


            return n;

        }
       



        /* A traduire en anglais */

        /// <summary>Retourne le nom d'une note</summary>
        /// <returns>Retourn un tableau de notes 
        /// 0=nom
        /// 1=Alteration
        /// 2=Octave
        /// 3=Rythme
        /// 4=Pointure</returns>
        public string[] ToString(Langue langue)
        {
           
            string[] nom = new String[5];

            switch (note)
            {
                case Note.NoteEn.C:
                    if (langue == Langue.Fr) { nom[0] = "Do"; }
                    if (langue == Langue.En) { nom[0] = "C"; }
                    break;
                case Note.NoteEn.D:
                    if (langue == Langue.Fr) { nom[0] = "Re"; }
                    if (langue == Langue.En) { nom[0] = "D"; }
                    break;
                case Note.NoteEn.E:
                    if (langue == Langue.Fr) { nom[0] = "Mi"; }
                    if (langue == Langue.En) { nom[0] = "E"; }
                    break;
                case Note.NoteEn.F:
                    if (langue == Langue.Fr) { nom[0] = "Fa"; }
                    if (langue == Langue.En) { nom[0] = "F"; }
                    break;
                case Note.NoteEn.G:
                    if (langue == Langue.Fr) { nom[0] = "Sol"; }
                    if (langue == Langue.En) { nom[0] = "G"; }
                    break;
                case Note.NoteEn.A:
                    if (langue == Langue.Fr) { nom[0] = "La"; }
                    if (langue == Langue.En) { nom[0] = "A"; }
                    break;
                case Note.NoteEn.B:
                    if (langue == Langue.Fr) { nom[0] = "Si"; }
                    if (langue == Langue.En) { nom[0] = "B"; }
                    break;
                case Note.NoteEn.No:
                    if (langue == Langue.Fr) { nom[0] = "---"; }
                    if (langue == Langue.En) { nom[0] = "---"; }
                    break;
            }

            
            switch (alteration)
            {
                case Note.Alteration.Bemol:
                    nom[1] = "b";
                    break;
                case Note.Alteration.Diese:
                    nom[1] = "#";
                    break;
                case Note.Alteration.No:
                    nom[1] = "";
                    break;
                case Note.Alteration.Becard:
                    nom[1] = "bec";
                    break;
            }


           

            nom[2] = octave.ToString();

            switch (rythme)
            {
                case TypeRytmique.Ronde:
                    if (langue == Langue.Fr) { nom[3] = "Ronde"; }
                    if (langue == Langue.En) { nom[3] = "Rond"; }
                    break;

                case TypeRytmique.Blanche:
                    if (langue == Langue.Fr) { nom[3] = "Blanche"; }
                    if (langue == Langue.En) { nom[3] = "Blanch"; }
                    break;

                case TypeRytmique.Noire:
                    if (langue == Langue.Fr) { nom[3] = "Noire"; }
                    if (langue == Langue.En) { nom[3] = "Noir"; }
                    break;

                case TypeRytmique.Croche:
                    if (langue == Langue.Fr) { nom[3] = "Croche"; }
                    if (langue == Langue.En) { nom[3] = "Croche"; }
                    break;

                case TypeRytmique.DoubleCroche:
                    if (langue == Langue.Fr) { nom[3] = "Douche Croche"; }
                    if (langue == Langue.En) { nom[3] = "Douche Croche"; }
                    break;
                                    
                case TypeRytmique.TripleCroche:
                    if (langue == Langue.Fr) { nom[3] = "Triple Croche"; }
                    if (langue == Langue.En) { nom[3] = "Triple Croche"; }
                    break;

                case TypeRytmique.QuadrupleCroche:
                    if (langue == Langue.Fr) { nom[3] = "Quadruple Croche"; }
                    if (langue == Langue.En) { nom[3] = "Quadruple Croche"; }
                    break;
             

                /* TYPE SILENCE */

                case TypeRytmique.Pause:
                    if (langue == Langue.Fr) { nom[3] = "Pause"; }
                    if (langue == Langue.En) { nom[3] = "Pause"; }
                    break;

                case TypeRytmique.DemiPause:
                    if (langue == Langue.Fr) { nom[3] = "Demi-Pause"; }
                    if (langue == Langue.En) { nom[3] = "Demi-Pause"; }
                    break;

                case TypeRytmique.Soupir:
                    if (langue == Langue.Fr) { nom[3] = "Soupir"; }
                    if (langue == Langue.En) { nom[3] = "Soupir"; }
                    break;

                case TypeRytmique.DemiSoupir:
                    if (langue == Langue.Fr) { nom[3] = "Demi-Soupir"; }
                    if (langue == Langue.En) { nom[3] = "Demi-Soupir"; }
                    break;

                case TypeRytmique.QuartSoupir:
                    if (langue == Langue.Fr) { nom[3] = "Quart de Soupir"; }
                    if (langue == Langue.En) { nom[3] = "Quart of Soupir"; }
                    break;

                case TypeRytmique.HuitiemeSoupir:
                    if (langue == Langue.Fr) { nom[3] = "Huitième de soupir"; }
                    if (langue == Langue.En) { nom[3] = "Huitième de soupir"; }
                    break;

                case TypeRytmique.SeiziemeSoupir:
                    if (langue == Langue.Fr) { nom[3] = "Seizième de soupir"; }
                    if (langue == Langue.En) { nom[3] = "Seizième de soupir"; }
                    break;               
                         

               
            }

            switch (pointure)
            {
                case Pointure.No:
                    nom[4] = "";
                    break;
                case Pointure.Pointe:
                    if (langue == Langue.Fr) { nom[4] = "Pointé"; }
                    if (langue == Langue.En) { nom[4] = "Pointé"; }
                    break;
                case Pointure.DoublePointe:
                     if (langue == Langue.Fr) { nom[4] = "Doublement Pointé"; }
                     if (langue == Langue.En) { nom[4] = "Double Point"; }
                    break;
           
            };

            return nom;
        }


        /*faire aussi l'opérateur-- */
        public static Note operator ++(Note n)
        {
            switch (n.note)
            {
                case NoteEn.C:
                    if (n.alteration == Alteration.No || n.alteration == Alteration.Becard) { n.note = NoteEn.C; n.alteration = Alteration.Diese; break; }
                    if (n.alteration == Alteration.Diese) { n.note = NoteEn.D; n.alteration = Alteration.No; break; }
                    if (n.alteration == Alteration.Bemol) { n.note = NoteEn.C; n.alteration = Alteration.No; break; }
                    break;
                case NoteEn.D:
                    if (n.alteration == Alteration.No || n.alteration == Alteration.Becard) { n.note = NoteEn.D; n.alteration = Alteration.Diese; break; }
                    if (n.alteration == Alteration.Diese) { n.note = NoteEn.E; n.alteration = Alteration.No; break; }
                    if (n.alteration == Alteration.Bemol) { n.note = NoteEn.D; n.alteration = Alteration.No; break; }
                    break;
                /*pas de demi temps entre Mi et Fa, Do et Si*/
                case NoteEn.E:
                    if (n.alteration == Alteration.No || n.alteration == Alteration.Becard) { n.note = NoteEn.F; n.alteration = Alteration.No; break; }
                    if (n.alteration == Alteration.Diese) { n.note = NoteEn.F; n.alteration = Alteration.Diese; break; }
                    if (n.alteration == Alteration.Bemol) { n.note = NoteEn.E; n.alteration = Alteration.No; break; }
                    break;
                case NoteEn.F:
                    if (n.alteration == Alteration.No || n.alteration == Alteration.Becard) { n.note = NoteEn.F; n.alteration = Alteration.Diese; break; }
                    if (n.alteration == Alteration.Diese) { n.note = NoteEn.G; n.alteration = Alteration.No; break; }
                    if (n.alteration == Alteration.Bemol) { n.note = NoteEn.F; n.alteration = Alteration.No; break; }
                    break;
                case NoteEn.G:
                    if (n.alteration == Alteration.No || n.alteration == Alteration.Becard) { n.note = NoteEn.G; n.alteration = Alteration.Diese; break; }
                    if (n.alteration == Alteration.Diese) { n.note = NoteEn.A; n.alteration = Alteration.No; break; }
                    if (n.alteration == Alteration.Bemol) { n.note = NoteEn.G; n.alteration = Alteration.No; break; }
                    break;
                case NoteEn.A:
                    if (n.alteration == Alteration.No || n.alteration == Alteration.Becard) { n.note = NoteEn.B; n.alteration = Alteration.Bemol; break; }
                    if (n.alteration == Alteration.Diese) { n.note = NoteEn.B; n.alteration = Alteration.No; break; }
                    if (n.alteration == Alteration.Bemol) { n.note = NoteEn.A; n.alteration = Alteration.No; break; }
                    break;
                case NoteEn.B:
                    if (n.octave < 9) {

                        if (n.alteration == Alteration.No || n.alteration == Alteration.Becard) { n.note = NoteEn.C; n.alteration = Alteration.No; n.octave++; break; }
                        if (n.alteration == Alteration.Diese) { n.note = NoteEn.C; n.alteration = Alteration.Diese; n.octave++; break; }
                        if (n.alteration == Alteration.Bemol) { n.note = NoteEn.B; n.alteration = Alteration.No; break; }
                    }
                    else { Console.WriteLine("[Exception modele Note] operator++ erreur: limite des octaves"); }
                    break;
            }

            n.freqHz = n.toFreq();
            return n;
        }



    }





}
